﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BitConversion
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        /// <summary>
        /// Should the byte pairs be swapped?
        /// </summary>
        bool isByteSwapped = false;

        private void btn_Calculate_Click(object sender, RoutedEventArgs e)
        {
            //If the user wants to swap the byte pairs as part of the conversion, let's store that in a global variable
            isByteSwapped = (bool)chk_ByteSwap.IsChecked;
            //In case the conversion fails, let's display a nice message - there are better ways to do this, but it's quick and easy for demonstration purposes
            try
            {
                //Let's perform the appropriate conversion based on the conversion method the user selected from the ComboBox
                switch (cbo_Conversion.SelectedIndex)
                {
                    case 0:
                        uint16_to_byte(txt_Value.Text);
                        break;
                    case 1:
                        byte_to_uint16(txt_Value.Text);
                        break;
                    case 2:
                        uint32_to_byte(txt_Value.Text);
                        break;
                    case 3:
                        byte_to_uint32(txt_Value.Text);
                        break;
                    case 4:
                        single_to_byte(txt_Value.Text);
                        break;
                    case 5:
                        byte_to_single(txt_Value.Text);
                        break;
                    default:
                        //In case we add options to the ComboBox and don't have them coded, better to display an error than an invalid calculation
                        txt_Result.Text = "Option not coded yet.";
                        break;

                }
            }
            catch (Exception)
            {
                txt_Result.Text = "Invalid input. Try again.";
            }
        }

        /* -------------------------
         * All of the conversions below follow the same general logic in one of two directions:
         *  1. Get the input text string
         *  2. PARSE the input text string as the expected input type (eg. in UInt16 to Byte[], the input type we will convert to is UInt16)
         *  (If the input type was a Byte[], do the byte swapping now)
         *  3. Convert to the appropriate output data type (eg. in UInt16 to Byte[] the output type is Byte[])
         *  (If the output type was a Byte[], do the byte swapping now)
         *  4. Print the output value to the Result text box
         * --------------------------
         */

        #region UInt16
        private byte[] uint16_to_byte(object input){
            //Parse the input (text) as the expected input type for our conversion (UInt16)
            UInt16 myShort = Convert.ToUInt16(input);
            //Convert the input UInt16 to Bytes
            byte[] myBytes = BitConverter.GetBytes(myShort);
            //If the user requested byte swapping, perform the swaps
            if (isByteSwapped) myBytes = SwapBytePairs(myBytes);
            //Print the output bytes to the Result text box
            txt_Result.Text = BitConverter.ToString(myBytes);
            //Also return the bytes (future proofing the function)
            return myBytes;
        }

        private UInt16 byte_to_uint16(object input)
        {
            byte[] myBytes = StringToByteArray((string)input);
            if (isByteSwapped) myBytes = SwapBytePairs(myBytes);
            UInt16 myShort = BitConverter.ToUInt16(myBytes, 0);
            txt_Result.Text = myShort.ToString();
            return myShort;
        }
        #endregion



        #region UInt32
        private byte[] uint32_to_byte(object input)
        {
            UInt32 myInt = Convert.ToUInt32(input);
            byte[] myBytes = BitConverter.GetBytes(myInt);
            if (isByteSwapped) myBytes = SwapBytePairs(myBytes);
            txt_Result.Text = BitConverter.ToString(myBytes);
            return myBytes;
        }

        private UInt32 byte_to_uint32(object input)
        {
            byte[] myBytes = StringToByteArray((string)input);
            if (isByteSwapped) myBytes = SwapBytePairs(myBytes);
            UInt32 myInt = BitConverter.ToUInt32(myBytes, 0);
            txt_Result.Text = myInt.ToString();
            return myInt;
        }
        #endregion



        #region Single Precision Float
        private byte[] single_to_byte(object input)
        {
            Single mySingle = Convert.ToSingle(input);
            byte[] myBytes = BitConverter.GetBytes(mySingle);
            if (isByteSwapped) myBytes = SwapBytePairs(myBytes);
            txt_Result.Text = BitConverter.ToString(myBytes);
            return myBytes;
        }

        private Single byte_to_single(object input)
        {
            byte[] myBytes = StringToByteArray((string)input);
            if (isByteSwapped) myBytes = SwapBytePairs(myBytes);
            Single mySingle = BitConverter.ToSingle(myBytes, 0);
            txt_Result.Text = mySingle.ToString();
            return mySingle;
        }
        #endregion


        /// <summary>
        /// Converts a byte formatted string to a byte array. For example, string 'FF-00' becomes byte[] { 0xFF, 0x00 }
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        public static byte[] StringToByteArray(String hex)
        {
            hex = hex.Replace("-", "").Replace(" ", ""); //remove dashes and spaces
            int NumberChars = hex.Length / 2;
            byte[] bytes = new byte[NumberChars];
            StringReader sr = new StringReader(hex);
            for (int i = 0; i < NumberChars; i++)
                bytes[i] = Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
            sr.Dispose();
            return bytes;
        }

        /// <summary>
        /// Swap each byte pair. For example AA-BB-CC-DD becomes BB-AA-DD-CC
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>

        private byte[] SwapBytePairs(byte[] input)
        {
            byte[] output = new byte[input.Length];
            for (int i = 0; i < input.Length; i+=2)
            {
                output[i] = input[i+1];
                output[i+1] = input[i];
            }
            return output;
        }

        /// <summary>
        /// When the window is loaded, determine the endianess and display that on the form
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            if (BitConverter.IsLittleEndian)
            {
                lbl_Endianess.Content = "Little Endian (Intel)";
            }
            else
            {
                lbl_Endianess.Content = "Big Endian";
            }
        }

        /// <summary>
        /// Moves the content from the Result panel into the Input panel
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txt_Result_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            txt_Value.Text = txt_Result.Text;
        }
    }
}
